
#include <BAnimation>
#include "member_BAnimation.h"
#include "member_BChannel.h"

using namespace BWE;

#define member					(*(member_BAnimation*)_ptr)
#define member_allocate()		_ptr = new member_BAnimation(this)
#define member_release()		delete (member_BAnimation*)_ptr

BAnimation::BAnimation()
{
	member_allocate();
}
BAnimation::BAnimation(const BString& name)
{
	member_allocate();
	this->setName(name);
}
BAnimation::~BAnimation()
{
	member_release();
}

void BAnimation::setLoop(bool loop)
{
	member.loop = loop;
}
bool BAnimation::loop() const
{
	return member.loop;
}

void BAnimation::setDuration(double duration)
{
	member.duration = duration;
}
double BAnimation::duration() const
{
	return member.duration;
}

void BAnimation::reset()
{
	member.pause = true;
	member.time = 0;
	member.timeStart = 0;
	member.timePause = 0;
}
void BAnimation::start()
{
	member.pause = false;
}
void BAnimation::pause()
{
	member.pause = true;
}
void BAnimation::stop()
{
	reset();
}

double BAnimation::startTime() const
{
	return member.timeStart;
}
double BAnimation::passTime() const
{
	return member.time;
}
double BAnimation::remainTime() const
{
	return member.duration - member.time;
}

void BAnimation::addChannel(BChannel* channel)
{
	if (!member.channels.contain(channel))
	{
		member.channels.append(channel);
		if (channel_member(channel)->animation)
			channel_member(channel)->animation->removeChannel(channel);
		channel_member(channel)->animation = this;
	}
}
bool BAnimation::removeChannel(BChannel* channel)
{
	if (member.channels.contain(channel))
	{
		BChannelHolder holder = channel;
		channel_member(channel)->animation = 0;
		return member.channels.remove(channel);
	}
	return false;
}
bool BAnimation::removeChannel(const BString& name)
{
	for (int i = 0; i < member.channels.size(); i++)
	{
		BChannel* channel = member.channels[i];
		if (channel->name() == name)
		{
			return removeChannel(channel);
		}
	}
	return false;
}

void BAnimation::raisChannel(BChannel* channel)
{
	int index = member.channels.indexOf(channel);
	if (index > 0)
	{
		member.channels.swap(index, 0);
	}
}
void BAnimation::downChannel(BChannel* channel)
{
	int index = member.channels.indexOf(channel);
	if (index < member.channels.size() - 1)
	{
		member.channels.swap(index, member.channels.size() - 1);
	}
}

void BAnimation::stepRaisChannel(BChannel* channel)
{

}
void BAnimation::stepDownChannel(BChannel* channel)
{

}

void BAnimation::moveChannel(int originIndex, int targetIndex)
{
	//member.channels.move(originIndex, targetIndex);
}
void BAnimation::clearChannels()
{
	member.channels.clear();
	reset();
}

int BAnimation::channelCount() const
{
	return member.channels.size();
}
BChannel* BAnimation::channel(int index)
{
	return member.channels(index);
}
const BChannel* BAnimation::channel(int index) const
{
	return member.channels(index);
}

void BAnimation::apply()
{
	if (member.pause)
		return;
	for (int i = 0; i < member.channels.size(); i++)
	{
		BChannel* channel = member.channels[i];
		if (!channel->able())
			continue;
		if (channel->targetName().empty())
			continue;
		if (!channel_member(channel)->target)
			continue;
		channel->apply(channel_member(channel)->target);
	}
}
void BAnimation::fresh(double time)
{
	if (member.pause)
		return;

	if (bZero(member.duration))
		return;

	if (member.timeStart < 0.0001)
	{
		member.timeStart = time;
		member.time = 0;
	}

	bool over = false;
	time -= member.timeStart;
	if (time > member.duration)
	{
		if (member.loop)
		{
			time = fmodf(time, member.duration);
		}
		else
		{
			time = member.duration;
			over = true;
		}
	}
	for (int i = 0; i < member.channels.size(); i++)
	{
		BChannel* channel = member.channels[i];
		if (!channel->able())
			continue;
		channel->update(time);
	}
	if (over)
	{
		member.pause = true;
	}
}
